package com.remoter.transport.netty.filter;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.remoter.api.configure.IConfiguration;
import com.remoter.api.configure.support.AbstractConfiguration;
import com.remoter.api.context.IContextService;
import com.remoter.api.context.support.Exporter;
import com.remoter.api.extension.annotation.ExtensionName;
import com.remoter.api.extension.support.ExtensionLoader;
import com.remoter.api.protocol.support.RemoterRequest;
import com.remoter.api.protocol.support.RemoterResponse;
import com.remoter.api.transport.IMessageTaskFilter;
import com.remoter.api.util.Final;
import com.remoter.api.util.ObjectChain;
import com.remoter.api.util.ReflectUtils;
import com.remoter.api.util.RemoterServiceStatus;

@ExtensionName("executes")
public class ExecutesLimitFilter implements IMessageTaskFilter{
	
	private static final Logger logger = LoggerFactory.getLogger(ExecutesLimitFilter.class);
	
	private final IConfiguration configuration;
	private final IContextService contextService;
	public ExecutesLimitFilter(){
		this.configuration = AbstractConfiguration.getConfiguration();
		this.contextService = ExtensionLoader.getService(IContextService.class,this.configuration.getOption(Final.O_SERVER_CONTEXT));
	}
	
	@Override
	public void execute(RemoterRequest remoterRequest,RemoterResponse remoterResponse,ObjectChain<IMessageTaskFilter> chain){
		try{
			Class<?> type = ReflectUtils.forName(remoterRequest.getServiceClass());
			Exporter exporter = this.contextService.getExporter(remoterRequest.getServiceBeanName(),type);
			String methodName = remoterRequest.getServiceMethodName();
			if(null != exporter){
				int max = exporter.getExecutes();
				if(max > 0){
					RemoterServiceStatus count = RemoterServiceStatus.getStatus(exporter,methodName);
					logger.debug("exporter for "+ exporter +" allow max executes = " + max + " and current executes = " + count.getActive());
					if(count.getActive() >= max){
						remoterResponse.setException("failed to invoker method " + methodName + " in provider " + exporter.getPath() + " allow max executes = " + max + " and current executes = " + count.getActive());
					}
				}
				RemoterServiceStatus.beginCount(exporter,methodName);
				long begin = System.currentTimeMillis();
				boolean isException = false;
				try{
					chain.next().execute(remoterRequest, remoterResponse, chain);
					isException = false;
				}catch(Exception e){
					isException = true;
					logger.warn(e.getMessage(),e);
				}finally{
					RemoterServiceStatus.endCount(exporter, methodName, System.currentTimeMillis() - begin, isException);
				}
			}else{
				remoterResponse.setException("exporter get error in provider " + remoterRequest.getServiceClass()+"."+methodName);
			}
		}catch(Exception e){
			remoterResponse.setException(e.getMessage());
		}
	}
	
}